﻿/**************************************************
 * 文 件 名：SqlHelper.cs
 * 版    本：V1.0
 * 创 建 人：杨书林
 * 日    期：2011-7-5
 * 说    明：SqlHelper 类是 IDbHelper 接口的实现类

 * 修 改 人：
 * 日    期：
 * 描    述：
 **************************************************/
using System;
using System.Data;
using System.Data.SqlClient;

namespace Ysl.Data.DbHelper
{
    /// <summary>
    /// SqlHelper
    /// 提供了一组有关 SQL Server 的数据库操作方法
    /// </summary>
    internal class SqlHelper : DbHelperBase, IDbHelper
    {
        #region 构造函数
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="connectionString">数据库连接字符串</param>
        internal SqlHelper(string connectionString)
            : base(connectionString, DbProviderNames.System_Data_SqlClient)
        {
        }
        #endregion

        #region 组织参数及相关方法
        /// <summary>
        /// 参数名称前加参数标识符
        /// </summary>
        /// <param name="parameterName">参数名称</param>
        /// <returns>返回string类型</returns>
        public override string AddParameterToken(string parameterName)
        {
            return "@" + parameterName;
        }

        /// <summary>
        /// 获取存储过程参数集
        /// </summary>
        /// <param name="procedureName">存储过程名称</param>
        /// <param name="includeReturnValueParameter">是否包含返回值参数（true表示包含，false表示不包含，默认为false）</param>
        /// <returns>返回IDbDataParameter[]类型</returns>
        public override IDbDataParameter[] GetProcedureParameters(string procedureName, bool includeReturnValueParameter)
        {
            //打开连接
            IDbConnection connection = this.OpenConnection();

            //创建DbCommand命令
            SqlCommand command = (SqlCommand)connection.CreateCommand();
            command.CommandType = CommandType.StoredProcedure;
            command.CommandText = procedureName;

            //从指定的存储过程中获取参数信息并填充指定的SqlCommand的对象的指定Parameter集中
            SqlCommandBuilder.DeriveParameters(command);

            if (!includeReturnValueParameter)
            {
                //移除默认的返回值参数
                command.Parameters.RemoveAt(0);
            }

            //如果将一个DbCommand对象的Parameters插入到另外一个DbCommand对象中时，会发生 “另一个 SqlParameterCollection 中已包含 SqlParameter。”错误 错误的原因是：.Net Framework限制了两个IDataParameterCollection指向同一个对象
            //解决办法:
            //解决方法1：在每一次循环时，重新生成对象，但这样会产生大量的垃圾变量，不可取
            //解决方法2：深拷贝，例如：DbParameter p = (DbParameter)((ICloneable)param).Clone();
            //解决方法3：将使用完之后的Command命令的Parameters集合清空
            IDbDataParameter[] discoveredParameters = new SqlParameter[command.Parameters.Count];
            command.Parameters.CopyTo(discoveredParameters, 0);
            command.Parameters.Clear();     //解决方法2

            //for (int i = 0; i < command.Parameters.Count; i++)        //解决方法3
            //{
            //    discoveredParameters[i] = (SqlParameter)((ICloneable)command.Parameters[i]).Clone();
            //}

            foreach (IDbDataParameter discoveredParameter in discoveredParameters)
            {
                //用DBNull初始化参数
                discoveredParameter.Value = DBNull.Value;
            }

            return discoveredParameters;
        }

        #endregion
    }
}
